#include "StdAfx.h"
#include "ListUI.h"
#include "ControlUI.h"
#include "ListHeaderUI.h"
#include "ListFooterUI.h"
#include "WhiteCanvasUI.h"
#include "LabelPanelUI.h"
#include "PaddingPanelUI.h"


CListUI::CListUI(void):  /*m_pImage(NULL),*/m_pCallback(NULL), m_iCurSel(-1), m_iExpandedItem(-1)
{
	m_pList = new CVerticalLayoutUI;
	m_pHeader = new CListHeaderUI;
	//m_pFooter = new CListFooterUI;

	CWhiteCanvasUI* pWhite = new CWhiteCanvasUI;
	pWhite->Add(m_pList);

	//m_pFooter->Add(new CLabelPanelUI);
	//m_pFooter->Add(new CPaddingPanelUI);

	Add(m_pHeader);
	CVerticalLayoutUI::Add(pWhite);
	//Add(m_pFooter);

	m_pList->EnableScrollBar(true);

	::ZeroMemory(&m_ListInfo, sizeof(TListInfoUI));
}

CListUI::~CListUI(void)
{
}

LPCTSTR CListUI::GetClass() const
{
	return _T("ListUI");
}

UINT CListUI::GetControlFlags() const
{
	return UIFLAG_TABSTOP;
}

LPVOID CListUI::GetInterface(LPCTSTR pstrName)
{
	if( _tcscmp(pstrName, _T("List")) == 0 ) return static_cast<IListUI*>(this);
	if( _tcscmp(pstrName, _T("ListOwner")) == 0 ) return static_cast<IListOwnerUI*>(this);
	return CVerticalLayoutUI::GetInterface(pstrName);
}

bool CListUI::Add(CControlUI* pControl)
{
	// Override the Add() method so we can add items specifically to
	// the intended widgets. Headers and footers are assumed to be
	// answer the correct interface so we can add multiple list headers/footers.
	if( pControl->GetInterface(_T("ListHeader")) != NULL ) return CVerticalLayoutUI::Add(pControl);
	if( pControl->GetInterface(_T("ListFooter")) != NULL ) return CVerticalLayoutUI::Add(pControl);
	// We also need to recognize header sub-items
	if( _tcsstr(pControl->GetClass(), _T("Header")) != NULL ) return m_pHeader->Add(pControl);
	//if( _tcsstr(pControl->GetClass(), _T("Footer")) != NULL ) return m_pFooter->Add(pControl);
	// The list items should know about us
	IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(_T("ListItem")));
	if( pListItem != NULL ) {
		pListItem->SetOwner(this);
		pListItem->SetIndex(GetCount());
	}
	return m_pList->Add(pControl);
}

bool CListUI::Remove(CControlUI* pControl)
{
	ASSERT(!"Not supported yet");
	return false; 
}

void CListUI::RemoveAll()
{
	m_iCurSel = -1;
	m_iExpandedItem = -1;
	m_pList->RemoveAll();
}

CControlUI* CListUI::GetItem(int iIndex) const
{
	return m_pList->GetItem(iIndex);
}

int CListUI::GetCount() const
{
	return m_pList->GetCount();
}

void CListUI::SetPos(RECT rc1)
{
	RECT rc = rc1;
	rc.top = 93;
	////rc.left = 0;
	////rc.right = 600;
	rc.bottom = 320;

	CVerticalLayoutUI::SetPos(rc);
	if( m_pHeader == NULL ) return;
	// Determine general list information and the size of header columns
	m_ListInfo.Text = UICOLOR_CONTROL_TEXT_NORMAL;
	m_ListInfo.Background = UICOLOR__INVALID;
	//m_ListInfo.Background = UICOLOR_BUTTON_TEXT_NORMAL;
	m_ListInfo.SelText = UICOLOR_CONTROL_TEXT_SELECTED;
	m_ListInfo.SelBackground = UICOLOR_CONTROL_BACKGROUND_SELECTED;
	m_ListInfo.HotText = UICOLOR_CONTROL_TEXT_NORMAL;
	m_ListInfo.HotBackground = UICOLOR_CONTROL_BACKGROUND_HOVER;   
	m_ListInfo.nColumns = MIN(m_pHeader->GetCount(), UILIST_MAX_COLUMNS);
	// The header/columns may or may not be visible at runtime. In either case
	// we should determine the correct dimensions...
	if( m_pHeader->IsVisible() )
	{
		for(int i = 0; i < m_ListInfo.nColumns; i++) 
			m_ListInfo.rcColumn[i] = m_pHeader->GetItem(i)->GetPos();
	}
	else
	{
		RECT rcCol = { rc.left, 0, rc.left, 0 };
		for( int i = 0; i < m_ListInfo.nColumns; i++ ) {
			SIZE sz = m_pHeader->GetItem(i)->EstimateSize(CStdSize(rc.right - rc.left, rc.bottom - rc.top));
			rcCol.right += sz.cx;
			m_ListInfo.rcColumn[i] = rcCol;
			::OffsetRect(&rcCol, sz.cx, 0);
		}
	}
}

void CListUI::Event(TEventUI& event)
{
	switch( event.Type ) {
   case UIEVENT_KEYDOWN:
	   switch( event.chKey )
	   {
	   case VK_UP:
		   SelectItem(FindSelectable(m_iCurSel - 1, false));
		   EnsureVisible(m_iCurSel);
		   return;
	   case VK_DOWN:
		   SelectItem(FindSelectable(m_iCurSel + 1, true));
		   EnsureVisible(m_iCurSel);
		   return;
	   case VK_PRIOR:
		   SelectItem(FindSelectable(m_iCurSel - 10, false));
		   EnsureVisible(m_iCurSel);
		   return;
	   case VK_NEXT:
		   SelectItem(FindSelectable(m_iCurSel + 10, true));
		   EnsureVisible(m_iCurSel);
		   return;
	   case VK_HOME:
		   SelectItem(FindSelectable(0, false));
		   EnsureVisible(m_iCurSel);
		   return;
	   case VK_END:
		   SelectItem(FindSelectable(GetCount() - 1, true));
		   EnsureVisible(m_iCurSel);
		   return;
	   case VK_RETURN:
		   if( m_iCurSel != -1 ) GetItem(m_iCurSel)->Activate();
		   return;
	   }
	   break;
   case UIEVENT_SCROLLWHEEL:
	   {
		   switch( LOWORD(event.wParam) )
		   {
		   case SB_LINEUP:
			   SelectItem(FindSelectable(m_iCurSel - 1, false));
			   EnsureVisible(m_iCurSel);
			   return;
		   case SB_LINEDOWN:
			   SelectItem(FindSelectable(m_iCurSel + 1, true));
			   EnsureVisible(m_iCurSel);
			   return;
		   }
	   }
	   break;
	}
	CControlUI::Event(event);
}

CListHeaderUI* CListUI::GetHeader() const
{
	return m_pHeader;
}

CListFooterUI* CListUI::GetFooter() const
{
	return m_pFooter;
}

CContainerUI* CListUI::GetList() const
{
	return m_pList;
}

int CListUI::GetCurSel() const
{
	return m_iCurSel;
}

bool CListUI::SelectItem(int iIndex)
{
	if( iIndex == m_iCurSel ) return true;
	// We should first unselect the currently selected item
	if( m_iCurSel >= 0 ) {
		CControlUI* pControl = GetItem(m_iCurSel);
		if( pControl != NULL ) {
			IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(_T("ListItem")));
			if( pListItem != NULL ) pListItem->Select(false);
		}
	}
	// Now figure out if the control can be selected
	// TODO: Redo old selected if failure
	CControlUI* pControl = GetItem(iIndex);
	if( pControl == NULL ) return false;
	if( !pControl->IsVisible() ) return false;
	if( !pControl->IsEnabled() ) return false;
	IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(_T("ListItem")));
	if( pListItem == NULL ) return false;
	m_iCurSel = iIndex;
	if( !pListItem->Select(true) ) {
		m_iCurSel = -1;
		return false;
	}
	pControl->SetFocus();
	if( m_pManager != NULL ) {
		m_pManager->SendNotify(pControl, _T("itemclick"));
		m_pManager->SendNotify(this, _T("itemselect"));
	}
	Invalidate();
	return true;
}

const TListInfoUI* CListUI::GetListInfo() const
{
	return &m_ListInfo;
}

void CListUI::SetExpanding(bool bExpandable)
{
	m_ListInfo.bExpandable = bExpandable;
}

bool CListUI::ExpandItem(int iIndex, bool bExpand /*= true*/)
{
	if( !m_ListInfo.bExpandable ) return false;
	if( m_iExpandedItem >= 0 ) {
		CControlUI* pControl = GetItem(m_iExpandedItem);
		if( pControl != NULL ) {
			IListItemUI* pItem = static_cast<IListItemUI*>(pControl->GetInterface(_T("ListItem")));
			if( pItem != NULL ) pItem->Expand(false);
		}
		m_iExpandedItem = -1;
	}
	if( bExpand ) {
		CControlUI* pControl = GetItem(iIndex);
		if( pControl == NULL ) return false;
		if( !pControl->IsVisible() ) return false;
		IListItemUI* pItem = static_cast<IListItemUI*>(pControl->GetInterface(_T("ListItem")));
		if( pItem == NULL ) return false;
		m_iExpandedItem = iIndex;
		if( !pItem->Expand(true) ) {
			m_iExpandedItem = -1;
			return false;
		}
	}
	UpdateLayout();
	return true;
}

int CListUI::GetExpandedItem() const
{
	return m_iExpandedItem;
}

void CListUI::EnsureVisible(int iIndex)
{
	if( m_iCurSel < 0 ) return;
	RECT rcItem = m_pList->GetItem(iIndex)->GetPos();
	RECT rcList = m_pList->GetPos();
	int iPos = m_pList->GetScrollPos();
	if( rcItem.top >= rcList.top && rcItem.bottom < rcList.bottom ) return;
	int dx = 0;
	if( rcItem.top < rcList.top ) dx = rcItem.top - rcList.top;
	if( rcItem.bottom > rcList.bottom ) dx = rcItem.bottom - rcList.bottom;
	Scroll(0, dx);
}

void CListUI::Scroll(int dx, int dy)
{
	if( dx == 0 && dy == 0 ) return;
	m_pList->SetScrollPos(m_pList->GetScrollPos() + dy);
}

void CListUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
{
	if( _tcscmp(pstrName, _T("header")) == 0 ) GetHeader()->SetVisible(_tcscmp(pstrValue, _T("hidden")) != 0);
	else if( _tcscmp(pstrName, _T("footer")) == 0 ) GetFooter()->SetVisible(_tcscmp(pstrValue, _T("hidden")) != 0);
	else if( _tcscmp(pstrName, _T("expanding")) == 0 ) SetExpanding(_tcscmp(pstrValue, _T("true")) == 0);
	else CVerticalLayoutUI::SetAttribute(pstrName, pstrValue);
}

IListCallbackUI* CListUI::GetTextCallback() const
{
	return m_pCallback;
}

void CListUI::SetTextCallback(IListCallbackUI* pCallback)
{
	m_pCallback = pCallback;
}

